package com.yc.testupload.controller;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

import com.yc.testupload.util.DatabaseUtil;

/**
 * 数据库配置管理Servlet
 * 用于处理数据库配置的读取、保存和测试连接
 */
@WebServlet("/DatabaseConfigServlet")
public class DatabaseConfigServlet extends HttpServlet {
    private static final Logger logger = LogManager.getLogger(DatabaseConfigServlet.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final String CONFIG_FILE = "/database.properties";

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置响应类型为JSON
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        try {
            // 读取配置文件
            Properties properties = loadProperties();

            // 创建配置对象
            ConfigDTO configDTO = new ConfigDTO();
            configDTO.setDriver(properties.getProperty("jdbc.driver", ""));
            configDTO.setUrl(properties.getProperty("jdbc.url", ""));
            configDTO.setUsername(properties.getProperty("jdbc.username", ""));
            configDTO.setPassword(properties.getProperty("jdbc.password", ""));
            configDTO.setInitialSize(properties.getProperty("jdbc.initialSize", "5"));
            configDTO.setMaxActive(properties.getProperty("jdbc.maxActive", "20"));
            configDTO.setMaxIdle(properties.getProperty("jdbc.maxIdle", "10"));
            configDTO.setMinIdle(properties.getProperty("jdbc.minIdle", "5"));

            // 转换为JSON并响应
            String json = objectMapper.writeValueAsString(configDTO);
            response.getWriter().write(json);
        } catch (Exception e) {
            logger.error("读取数据库配置失败: {}", e.getMessage(), e);
            response.getWriter().write("{\"error\":\"" + e.getMessage() + "\"}");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置响应类型为JSON
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        try {
            // 获取请求参数中的action
            String action = request.getParameter("action");

            if ("test".equals(action)) {
                // 测试连接
                testDatabaseConnection(request, response);
            } else {
                // 保存配置
                saveDatabaseConfig(request, response);
            }
        } catch (Exception e) {
            logger.error("处理数据库配置请求失败: {}", e.getMessage(), e);
            response.getWriter().write("{\"success\":false,\"message\":\"" + e.getMessage() + "\"}");
        }
    }

    /**
     * 保存数据库配置
     */
    private void saveDatabaseConfig(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 读取请求体中的JSON配置
        JsonNode configJson = objectMapper.readTree(request.getReader());

        // 获取配置值
        String driver = configJson.get("driver").asText();
        String url = configJson.get("url").asText();
        String username = configJson.get("username").asText();
        String password = configJson.get("password").asText();
        String initialSize = configJson.get("initialSize").asText();
        String maxActive = configJson.get("maxActive").asText();
        String maxIdle = configJson.get("maxIdle").asText();
        String minIdle = configJson.get("minIdle").asText();

        // 验证必填字段
        if (driver.isEmpty() || url.isEmpty() || username.isEmpty()) {
            response.getWriter().write("{\"success\":false,\"message\":\"驱动、URL和用户名不能为空\"}");
            return;
        }

        try {
            // 保存到配置文件
            saveProperties(driver, url, username, password, initialSize, maxActive, maxIdle, minIdle);

            // 重新加载配置
            reloadDatabaseConfig();

            logger.info("数据库配置保存成功");
            response.getWriter().write("{\"success\":true,\"message\":\"配置保存成功\"}");
        } catch (Exception e) {
            logger.error("保存数据库配置失败: {}", e.getMessage(), e);
            response.getWriter().write("{\"success\":false,\"message\":\"" + e.getMessage() + "\"}");
        }
    }

    /**
     * 测试数据库连接
     */
    private void testDatabaseConnection(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 读取请求体中的JSON配置
        JsonNode configJson = objectMapper.readTree(request.getReader());

        // 获取配置值
        String driver = configJson.get("driver").asText();
        String url = configJson.get("url").asText();
        String username = configJson.get("username").asText();
        String password = configJson.get("password").asText();

        // 验证必填字段
        if (driver.isEmpty() || url.isEmpty() || username.isEmpty()) {
            response.getWriter().write("{\"success\":false,\"message\":\"驱动、URL和用户名不能为空\"}");
            return;
        }

        Connection conn = null;
        try {
            // 加载驱动
            Class.forName(driver);
            
            // 建立连接
            conn = DriverManager.getConnection(url, username, password);
            
            if (conn != null && !conn.isClosed()) {
                logger.info("数据库连接测试成功");
                response.getWriter().write("{\"success\":true,\"message\":\"数据库连接测试成功\"}");
            } else {
                response.getWriter().write("{\"success\":false,\"message\":\"数据库连接测试失败\"}");
            }
        } catch (ClassNotFoundException e) {
            logger.error("数据库驱动加载失败: {}", e.getMessage());
            response.getWriter().write("{\"success\":false,\"message\":\"驱动加载失败: " + e.getMessage() + "\"}");
        } catch (SQLException e) {
            logger.error("数据库连接测试失败: {}", e.getMessage());
            response.getWriter().write("{\"success\":false,\"message\":\"连接失败: " + e.getMessage() + "\"}");
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    logger.error("关闭连接失败: {}", e.getMessage());
                }
            }
        }
    }

    /**
     * 加载配置文件
     */
    private Properties loadProperties() throws IOException {
        Properties properties = new Properties();
        
        try {
            // 1. 首先尝试从系统属性指定的路径读取配置文件（JAR环境）
            String externalConfigPath = System.getProperty("database.config.path");
            if (externalConfigPath != null) {
                File externalConfig = new File(externalConfigPath);
                if (externalConfig.exists()) {
                    try (FileInputStream input = new FileInputStream(externalConfig)) {
                        properties.load(input);
                        return properties; // 如果成功加载外部配置，则直接返回
                    }
                }
            }
            
            // 2. 如果外部配置不存在或加载失败，则从classpath读取默认配置
            try (InputStream input = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)) {
                if (input != null) {
                    properties.load(input);
                }
            }
        } catch (IOException e) {
            logger.error("加载配置文件失败: {}", e.getMessage());
            // 继续执行，返回空的properties
        }
        
        return properties;
    }

    /**
     * 保存配置到文件
     */
    private void saveProperties(String driver, String url, String username, String password,
                              String initialSize, String maxActive, String maxIdle, String minIdle) throws IOException {
        Properties properties = new Properties();
        
        // 设置新的配置值
        properties.setProperty("# 数据库连接配置", "");
        properties.setProperty("# MySQL数据库连接信息", "");
        properties.setProperty("jdbc.driver", driver);
        properties.setProperty("jdbc.url", url);
        properties.setProperty("jdbc.username", username);
        properties.setProperty("jdbc.password", password);
        properties.setProperty("# 数据库连接池配置", "");
        properties.setProperty("jdbc.initialSize", initialSize);
        properties.setProperty("jdbc.maxActive", maxActive);
        properties.setProperty("jdbc.maxIdle", maxIdle);
        properties.setProperty("jdbc.minIdle", minIdle);
        
        // 保存到文件 - 使用备用路径策略
        URL configUrl = getClass().getClassLoader().getResource(CONFIG_FILE);
        if (configUrl != null && "file".equals(configUrl.getProtocol())) {
            // 开发环境：文件系统中存在配置文件
            try (FileOutputStream output = new FileOutputStream(configUrl.getPath())) {
                properties.store(output, "数据库配置");
            }
        } else {
            // 生产环境：JAR包中运行或配置文件不存在
            // 将配置文件保存到应用程序运行目录
            String filePath = new File(".").getAbsolutePath() + CONFIG_FILE;
            // 确保目录存在
            File configFile = new File(filePath);
            File parentDir = configFile.getParentFile();
            if (parentDir != null && !parentDir.exists()) {
                parentDir.mkdirs();
            }
            
            try (FileOutputStream output = new FileOutputStream(filePath)) {
                properties.store(output, "数据库配置");
            }
            
            // 更新CONFIG_FILE路径以指向新保存的文件
            System.setProperty("database.config.path", filePath);
        }
    }

    /**
     * 重新加载数据库配置
     */
    private void reloadDatabaseConfig() {
        // 调用DatabaseUtil的reloadConfiguration方法重新加载配置
        boolean success = DatabaseUtil.reloadConfiguration();
        if (success) {
            logger.info("数据库配置已成功重新加载");
            // 测试新配置是否生效
            DatabaseUtil.testConnection();
        } else {
            logger.error("数据库配置重新加载失败");
        }
    }

    /**
     * 配置DTO类，用于JSON序列化和反序列化
     */
    private static class ConfigDTO {
        private String driver;
        private String url;
        private String username;
        private String password;
        private String initialSize;
        private String maxActive;
        private String maxIdle;
        private String minIdle;

        // Getters and Setters
        public String getDriver() { return driver; }
        public void setDriver(String driver) { this.driver = driver; }
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public String getInitialSize() { return initialSize; }
        public void setInitialSize(String initialSize) { this.initialSize = initialSize; }
        public String getMaxActive() { return maxActive; }
        public void setMaxActive(String maxActive) { this.maxActive = maxActive; }
        public String getMaxIdle() { return maxIdle; }
        public void setMaxIdle(String maxIdle) { this.maxIdle = maxIdle; }
        public String getMinIdle() { return minIdle; }
        public void setMinIdle(String minIdle) { this.minIdle = minIdle; }
    }
}